﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using SocketLib.Buffers;

namespace SocketLib
{
    public class Client2
    {
        private byte[] buff = new byte[1024 * 1024];//64K
        Socket socket;

        CircularBuffer cb = new CircularBuffer();


        #region 事件委托
        public delegate void ConnectCallbackDelegate();
        public event ConnectCallbackDelegate ConnectCallbackEventHandler;
        public delegate void CallbackDelegate(object sender, CallbackEventArgs e);
        public event CallbackDelegate Callback_EventHandler;
        public class CallbackEventArgs : EventArgs
        {
            //public IPMPack pack { get; set; }
            public byte[] buffer { get; set; }

        }

        public delegate void ReceiveDelegate(object sender, ReceiveEventArgs e);
        public event ReceiveDelegate ReceiveEventHandler;

        public class ReceiveEventArgs : EventArgs
        {
            public string msg { get; set; }
            public string ip { get; set; }
        }

        public class ConnectCallbackEventArgs : EventArgs
        {

            public string msg { get; set; }
            public string ip { get; set; }
        }





        #endregion

        public void Connect(string host, int port)
        {
            IPAddress ip = IPAddress.Parse(host);
            IPEndPoint ipe = new IPEndPoint(ip, port);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.BeginConnect(ipe, new AsyncCallback(ConnectCallback), socket);

            try
            {
                socket.BeginReceive(buff, 0, buff.Length, SocketFlags.None, new AsyncCallback(Receive2), socket);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                
            }
            ThreadPool.QueueUserWorkItem(new WaitCallback(AnalysisbufferPool));

        }

        #region SendMsg
        public void Send(string data)
        {
            byte[] byteData = System.Text.Encoding.ASCII.GetBytes(data);
            socket.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), socket);

        }

        public void SendMsg(string msg)
        {

            SendMsg(msg, 1);
        }

        public void SendMsg(string msg, int packType)
        {

            SendMsg(msg, 1, DateTime.Now.Millisecond);

        }

        public void SendMsg(string msg, int packType, int packNo)
        {

            byte[] data = Encoding.Default.GetBytes(msg);
            IPMPack sendIPMPack = new IPMPack();
            sendIPMPack.PackType = packType;
            //sendIPMPack.PackSize = data.Length;
            sendIPMPack.PackNo = packNo;
            sendIPMPack.Data = data;
            byte[] b = sendIPMPack.Packed();
            socket.BeginSend(b, 0, b.Length, 0, new AsyncCallback(SendCallback), socket);

        }

        #endregion



        private void SendCallback(System.IAsyncResult ar)
        {
            try
            {
                Socket client = (Socket)ar.AsyncState;
                int bytesSend = client.EndSend(ar);
                //Console.WriteLine("Send {0} bytes to server.", bytesSend);
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message.ToString());
            }

        }


        private void ConnectCallback(IAsyncResult e)
        {
            if (ConnectCallbackEventHandler != null)
            {
                ConnectCallbackEventHandler();

            }

            Socket client = (Socket)e.AsyncState;
            //client.EndConnect(e);
            client.BeginReceive(buff, 0, buff.Length, SocketFlags.None, new AsyncCallback(Receive2), client);


        }


        private void Receive2(IAsyncResult ar)
        {
            Socket client = (Socket)ar.AsyncState;
            try
            {

                int revCount = client.EndReceive(ar);

                //int a = client.Available;

                if (revCount > 0)
                {
                    
                    Byte[] a = new Byte[revCount];
                    Buffer.BlockCopy(buff, 0, a, 0, revCount);
                    cb.Write(a, 0, a.Length);    

                }


                client.BeginReceive(buff, 0, buff.Length, SocketFlags.None, new AsyncCallback(Receive2), client);

            }
            catch (SocketException ex)
            {
                if (ex.ErrorCode == 10054)
                {
                    //throw new SocketLib.ex.ClientClosedException(ex.Message);
                    // Disconnect(client);

                }
            }
            finally
            {

            }
        }


        public void Closed()
        {
            socket.Close();
        }


        /// <summary>
        /// 目前这个解析最快
        /// </summary>
        /// <param name="o"></param>
        public void AnalysisbufferPool(object o)
        {

            while (true)
            {
                //取出包的大小
                //Thread.Sleep(500);
                byte[] b1 = cb.Read(0, 4);

                if (b1 == null)
                    continue;

                int len = BitConverter.ToInt32(b1, 0);
                
                byte[] data = cb.Read(0, len-4);

                byte[] byteDate = new byte[len+4];
                Buffer.BlockCopy(b1, 0, byteDate, 0, 4);

                Buffer.BlockCopy(data, 0, byteDate, 4, data.Length);


                //把完整的包发过去处理
                if (Callback_EventHandler != null)
                {
                    CallbackEventArgs args = new CallbackEventArgs();
                    args.buffer = byteDate;
                    Callback_EventHandler(this, args);
                }


            }
        }



    }
}

